-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: allow patch state to take in multiple patches + access key and account patching #124
base: main
Are you sure you want to change the base?
feat: allow patch state to take in multiple patches + access key and account patching #124
Conversation
now using ensure_sandbox_bin() instead of installing it every time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks so much for getting this implementation in! Did a cursory look and left a few comments so we can improve the maintainability of it
workspaces/build.rs
Outdated
// using unwrap because all the useful error messages are hidden inside | ||
near_sandbox_utils::ensure_sandbox_bin().unwrap(); | ||
// previously the next line was causing near sandbox to be installed every time cargo build/check was called | ||
// near_sandbox_utils::install().expect("Could not install sandbox"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice, but can you remove the comments surrounding it and also change the unwrap to an expect, since the error messages can be confusing at times when they don't give context:
// using unwrap because all the useful error messages are hidden inside | |
near_sandbox_utils::ensure_sandbox_bin().unwrap(); | |
// previously the next line was causing near sandbox to be installed every time cargo build/check was called | |
// near_sandbox_utils::install().expect("Could not install sandbox"); | |
near_sandbox_utils::ensure_sandbox_bin().expect("Could not install sandbox"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I agree about the context part, but there also should be a note of 'precise' reason of failure.
I'll try to do something like "Could not install sandbox. Reason: ... "
That sounds good?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
workspaces/src/network/sandbox.rs
Outdated
pub(crate) fn patch_state(&self, account_id: AccountId) -> SandboxPatchStateBuilder { | ||
SandboxPatchStateBuilder::new(self, account_id) | ||
} | ||
|
||
pub(crate) fn patch_account(&self, account_id: AccountId) -> SandboxPatchStateAccountBuilder { | ||
SandboxPatchStateAccountBuilder::new(self, account_id) | ||
} | ||
|
||
pub(crate) fn patch_access_key( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you also include some tests for these various patches just so we can get some confidence that they're working as expected. You can probably reuse a bunch of the test code found in tests/patch_state.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we didn't tested because we waited for the feedback. Tests will be added too.
workspaces/src/worker/impls.rs
Outdated
pub async fn patch_state_multiple( | ||
&self, | ||
account_id: &AccountId, | ||
kvs: impl IntoIterator<Item = (impl Into<Vec<u8>>, impl Into<Vec<u8>>)>, | ||
) -> anyhow::Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if I'm a fan of taking an IntoIterator
as a parameter, but this might be the only way I can think of doing this.
@matklad @austinabell, would you have to know of anything better than this? Or if there's a better API design than having a separate function just be for the iterator
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, for the same rationale as #124 (comment) but primarily that the API will transition away from requiring owned Vec<u8>
and will be a breaking change down the road to change. Prob best to constrain to &[u8]
for now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You want impl std::iter::Extend
here.
workspaces/src/network/sandbox.rs
Outdated
// self | ||
// } | ||
|
||
pub async fn apply(self) -> anyhow::Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename the function to transact
to be more consistent with other Transaction
objects
pub async fn apply(self) -> anyhow::Result<()> { | |
pub async fn transact(self) -> anyhow::Result<()> { |
workspaces/src/worker/impls.rs
Outdated
key: impl Into<Vec<u8>>, | ||
value: impl Into<Vec<u8>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not everything will impl an Into<Vec<u8>>
and by that notion won’t fit all cases. Best to keep as-is to avoid that situation, since in rust a lot of things can be converted into a series of bytes &[u8]
including Vec<u8>
. This will also avoid having to make a breaking change for this since now people would have to require this trait impl.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah these traits are not as intuitive for a developer to read as well as it sticks us with using this API even when we remove the requirement for bytes to be converted to Vec<u8>
workspaces/src/worker/impls.rs
Outdated
/// Patch state into the sandbox network, using builder pattern. This will allow us to set | ||
/// state that we have acquired in some manner. This allows us to test random cases that | ||
/// are hard to come up naturally as state evolves. | ||
pub fn patch_state_builder(&self, account_id: &AccountId) -> SandboxPatchStateBuilder { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think it's better just to have one patch_state
function that way we can be consistent and have a defacto way of doing patching state. Let's merge this one and the other and just have this builder like one be the default
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's merge this one and the other
which 'other' one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant we can merge both patch_state and patch_state_builder to be just patch_state(AccountId) -> Builder. Would be a breaking API change, but it's fine since it would align with the other builder functions, and better to be consistent that way
workspaces/src/network/sandbox.rs
Outdated
} | ||
} | ||
|
||
pub fn data(mut self, key: impl Into<Vec<u8>>, value: impl Into<Vec<u8>>) -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
impl Into<Vec<u8>>
looks weird. Is there some precedent for such API shape? I'd just use Vec<u8>
or &[u8]
, with a strong preference for &[u8]
.
Vec<u8>
leaks impl details and forces needless allocation -- ideally, we don't store intermediate vecs at all and just build request string.
workspaces/src/network/sandbox.rs
Outdated
pub fn data_multiple( | ||
mut self, | ||
kvs: impl IntoIterator<Item = (impl Into<Vec<u8>>, impl Into<Vec<u8>>)>, | ||
) -> Self { | ||
let Self { | ||
ref mut records, | ||
ref account_id, | ||
.. | ||
} = self; | ||
records.extend(kvs.into_iter().map(|(key, value)| StateRecord::Data { | ||
account_id: account_id.clone(), | ||
data_key: key.into(), | ||
value: value.into(), | ||
})); | ||
self | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather let the caller to call .data
in a loop. If we need multi-item API, I'd go for
impl std::iter::Extend<(&'_ [u8], &'_ [u8])> for SandboxPatchStateBuilder<'_> {
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with calling data in a loop (it does not make it ergonomic for cases where you have a vec of values tho), but I don't understand why this impl std::iter::Extend<(&'_ [u8], &'_ [u8])>
is better than my .data_multiple
- while being a little more rust-idiomatic it does not allowing it to be called in a builder chain and looks imo worse than .data_multiple
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point about the builder!
Indeed, to look at the std, theer's
- https://doc.rust-lang.org/stable/std/process/struct.Command.html#method.arg
- https://doc.rust-lang.org/stable/std/process/struct.Command.html#method.args
Though, in this case, data_multiple
looks like a particualr awkward name (data itself is plural).
Maybe we want .entry
and .entries
here?
I'll delegate to you/dev-platform folks to make a judgement call here :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for .entry
and .entries
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for
.entry
and.entries
got it
workspaces/src/network/sandbox.rs
Outdated
} | ||
} | ||
|
||
pub fn data(mut self, key: impl Into<Vec<u8>>, value: impl Into<Vec<u8>>) -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like we should have a way to delete key as well?
workspaces/src/network/sandbox.rs
Outdated
records.extend(kvs.into_iter().map(|(key, value)| StateRecord::Data { | ||
account_id: account_id.clone(), | ||
data_key: key.into(), | ||
value: value.into(), | ||
})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: there's logical duplication between the two methods, one could delegate to the other (or both could delegate to internal _state_record)
workspaces/src/worker/impls.rs
Outdated
pub async fn patch_state_multiple( | ||
&self, | ||
account_id: &AccountId, | ||
kvs: impl IntoIterator<Item = (impl Into<Vec<u8>>, impl Into<Vec<u8>>)>, | ||
) -> anyhow::Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You want impl std::iter::Extend
here.
Thanks a bunch for the feedback, @matklad 's guidance is looking great. This week we'll try to update this PR accordingly and then start testing when that's ok in terms of API and stuff. |
removed comments, Co-authored-by: Phuong Nguyen <[email protected]>
https://github.com/adsick/workspaces-rs into FIRT-13-allow-patch-state-to-take-in-multiple-patches
Co-authored-by: Phuong Nguyen <[email protected]>
…tate-to-take-in-multiple-patches
Hi, I'm working on #12 and #19. Now I feel like some review of what I've done would be great, please tell me what API is preferable and how to shape it (where to put stuff etc.).
Highlights:
now accepting wider variety of types by using
Into<Vec<u8>>
(for more see line 235 of sandbox.rs)
bonus: fixed long cargo check/build times issue by not installing the node every time - the issue was in the build.rs
Now I'm looking for some feedback to refine API 🙂